from fastapi import HTTPException

from src.database.models import Region
from src.region_service.schemas import (
    Upload_region_form,
    Region_schema,
    Region_schema_with_accountId,
    Output_edit_region_schema
)

from src.database.my_crud import My_crud

from src.user_service.service.auth import raise_401_error

region_crud = My_crud(Region)


class Region_service:
    async def create_region(
        self,
        payload: Upload_region_form,
        user_id: int
    ):
        await raise_401_error(user_id)

        if await region_crud.exist(
            filters=[
                Region.latitude_1 == payload.latitude_1,
                Region.longitude_1 == payload.longitude_1,
                Region.latitude_2 == payload.latitude_2,
                Region.longitude_2 == payload.longitude_2
            ]
        ):
            raise HTTPException(
                status_code=409,
                detail="this region exists"
            )

        region_record = Region_schema_with_accountId(
            accountId=user_id,
            **payload.model_dump()
        )

        record: Region_schema = await region_crud.create(
            region_record,
            Region_schema
        )
        record_dict = record.model_dump()
        record_dict["osmData"] = {
            "mapLink": f"0.0.0.0:8080/map?latitude={record.latitude_1}&longitude={record.longitude_1}&zoom=12",
            "boundingBox": [record.latitude_1, record.longitude_1, record.latitude_2, record.longitude_2],
            "pointsOfInterest": [
                {
                    "name": record.name,
                    "type": record.regionType,
                    "latitude": record.latitude_1,
                    "longitude": record.longitude_1
                }
            ]
        }
        return record_dict

    async def get_region(self, regionId: int, user_id: int):
        await raise_401_error(user_id)

        if not await region_crud.exist([Region.id == regionId]):
            raise HTTPException(
                status_code=404,
                detail="this region not found"
            )

        record: Region_schema_with_accountId = await region_crud.get(
            filters=[Region.id == regionId],
            Output_model=Region_schema_with_accountId
        )
        record_dict = record.model_dump()
        record_dict["osmData"] = {
            "mapLink": f"0.0.0.0:8080/map?latitude={record.latitude_1}&longitude={record.longitude_1}&zoom=12",
            "boundingBox": [record.latitude_1, record.longitude_1, record.latitude_2, record.longitude_2],
            "pointsOfInterest": [
                {
                    "name": record.name,
                    "type": record.regionType,
                    "latitude": record.latitude_1,
                    "longitude": record.longitude_1
                }
            ]
        }
        return record_dict

    async def edit_region(
        self,
        regionId: int,
        payload: Upload_region_form,
        user_id: int
    ):
        await raise_401_error(user_id)

        if not await region_crud.exist([Region.id == regionId]):
            raise HTTPException(
                status_code=404,
                detail="this region not found"
            )

        if await region_crud.exist(
            filters=[
                Region.id == regionId,
                Region.accountId != user_id
            ]
        ):
            raise HTTPException(
                status_code=401,
                detail="you haven't access to this record"
            )

        region: Region_schema = await region_crud.get(
            filters=[
                Region.id == regionId
            ],
            Output_model=Region_schema
        )

        if (
            region.latitude_1 != payload.latitude_1 or
            region.longitude_1 != payload.longitude_1 or
            region.latitude_2 != payload.latitude_2 or
            region.longitude_2 != payload.longitude_2
        ):
            if await region_crud.exist(
                filters=[
                    Region.latitude_1 == payload.latitude_1,
                    Region.longitude_1 == payload.longitude_1,
                    Region.latitude_2 == payload.latitude_2,
                    Region.longitude_2 == payload.longitude_2
                ]
            ):
                raise HTTPException(
                    status_code=409,
                    detail="this region has already created"
                )

        record: Output_edit_region_schema = await region_crud.patch(
            filters=[Region.id == regionId],
            new_data=payload.model_dump(exclude_none=True),
            Output_model=Output_edit_region_schema
        )
        record_dict = record.model_dump()
        record_dict["osmData"] = {
            "mapLink": f"0.0.0.0:8080/map?latitude={record.latitude_1}&longitude={record.longitude_1}&zoom=12",
            "boundingBox": [record.latitude_1, record.longitude_1, record.latitude_2, record.longitude_2],
            "pointsOfInterest": [
                {
                    "name": record.name,
                    "type": None,
                    "latitude": record.latitude_1,
                    "longitude": record.longitude_1
                }
            ]
        }
        return record_dict
        

    async def delete_region(self, regionId: int, user_id: int):
        await raise_401_error(user_id)

        if not await region_crud.exist([Region.id == regionId]):
            raise HTTPException(
                status_code=404,
                detail="this region not found"
            )

        if not await region_crud.exist(
            filters=[
                Region.id == regionId,
                Region.accountId == user_id
            ]
        ):
            raise HTTPException(
                status_code=401,
                detail="you haven't access to this record"
            )

        region = await region_crud.get(
            filters=[Region.id == regionId],
            Output_model=Region_schema
        )

        if await region_crud.exist([Region.parentRegion == region.name]):
            raise HTTPException(
                status_code=400,
                detail="this region is parent for another"
            )

        return await region_crud.remove([Region.id == regionId])

    # it's for weather
    async def edit_region_name(
        self,
        regionId: int,
        regionName: str
    ):

        return await region_crud.patch(
            [Region.id == regionId],
            new_data=dict(name=regionName),
        )
